package thread

import (
	"fmt"
	"strings"
	"time"

	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/logger"

	"ssdevice/common/constant"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
)

type DevSensorInsertThread struct {
}

var sensorTableName = models.SysDevSensor{}.TableName()

func (DevSensorInsertThread) Run(threadName string) {
	logger.Infof("启动线程 - %s.", threadName)

	go func() {
		dataList := make([]models.SysDevSensor, 0)
		for {
			// 插入及时处理
			time.Sleep(3 * time.Second)
			now := utils.GetNowTimeStr()
			items := constant.SensorInsCache.Items()
			constant.SensorInsCache.Clear()
			for sn, dataMap := range items {
				for k, v := range dataMap {
					dataList = append(dataList, genSensorIns(sn, k, v, now))
				}
				if len(dataList) > constant.ThreadBatchSize {
					// 批量处理数据
					dealDevSensorIns(dataList)
					// 清空(减少扩容)
					dataList = dataList[0:0]
				}
			}
			if len(dataList) > 0 {
				// 批量处理数据
				dealDevSensorIns(dataList)
				// 清空(减少扩容)
				dataList = dataList[0:0]
			}
		}
	}()
}

func genSensorIns(sn, k string, v interface{}, now string) models.SysDevSensor {
	dm := map[string]interface{}{k: v}
	// 自动类型
	typeOf := fmt.Sprintf("%T", v)
	// 注意if顺序
	if strings.Contains(typeOf, "[]") {
		typeOf = "array"
	} else if strings.Contains(typeOf, "map[string]interface") {
		typeOf = "object"
	} else if strings.Contains(typeOf, "string") {
		typeOf = "string"
	} else if strings.Contains(typeOf, "nil") {
		//typeOf = "nil"
		typeOf = ""
	} else if strings.Contains(typeOf, "bool") {
		typeOf = "boolean"
	} else {
		// 数字统一处理
		typeOf = "number"
	}
	return models.SysDevSensor{
		Id:     utils.SimpleUUID(),
		Sn:     sn,
		Key:    k,
		Label:  k,
		Type:   typeOf,
		Data:   utils.MapToBytes(dm),
		Schema: utils.MapToBytes(utils.GetObjectSchema(dm)["properties"].(map[string]interface{})),
		Config: utils.MapToBytes(utils.GetObjectConfig(dm)),
		//CreateTime: &now,
		//UpdateTime: &now,
		TimeInsStr: now,
	}
}

func dealDevSensorIns(dataList []models.SysDevSensor) {
	t1 := time.Now()
	// 添加变量
	//sensorM := &models.SysDevSensor{}
	//sensorM.Orm = env.Db
	//if err := sensorM.Add(dataList); err != nil {
	//	logger.Error(err)
	//}
	sql := "INSERT INTO " + sensorTableName + " (id, sn, key, label, type, data, schema, config, create_time, update_time) VALUES "
	valueSql := make([]string, 0)
	for _, s := range dataList {
		valueSql = append(valueSql, "('"+s.Id+"','"+s.Sn+"','"+s.Key+"','"+s.Label+"','"+s.Type+"','"+string(s.Data)+"'::jsonb,'"+string(s.Schema)+"'::jsonb,'"+string(s.Config)+"'::jsonb,'"+s.TimeInsStr+"','"+s.TimeInsStr+"')")
	}
	sql += strings.Join(valueSql, ",")
	if err := env.Db.Raw(sql).Scan(&scan).Error; err != nil {
		logger.Error(err)
	}
	logger.Infof("sensor批量添加%d. 耗时%v", len(dataList), time.Since(t1).Round(time.Millisecond))
	// 更新config
	t2 := time.Now()
	// 按设备聚合
	snMap := make(map[string]map[string]interface{})
	for _, sensor := range dataList {
		sn := sensor.Sn
		if _, ok := snMap[sn]; !ok {
			snMap[sn] = make(map[string]interface{})
		}
		utils.DeepMerge(utils.BytesToMap(sensor.Config), snMap[sn])
	}
	for sn, varConfigMap := range snMap {
		path := "{config,sensor}"
		dataStr := string(utils.MapToBytes(varConfigMap))
		sql := "update sys_dev_config set data = jsonb_set(data::jsonb, '" + path + "', jsonb_update(data #> '" + path + "', '" + dataStr + "' :: jsonb ) )  where dev_sn = '" + sn + "'"
		if err := env.Db.Raw(sql).Scan(&scan).Error; err != nil {
			logger.Error(err)
		}
	}
	logger.Infof("设备config更新%d. 耗时%v", len(snMap), time.Since(t2).Round(time.Millisecond))
}
